package com.thornbird.vehiclerecycling.controller;

import com.thornbird.vehiclerecycling.annotation.CurrentUser;
import com.thornbird.vehiclerecycling.config.OAuth2LoginConfig;
import com.thornbird.vehiclerecycling.entity.Config;
import com.thornbird.vehiclerecycling.entity.Order;
import com.thornbird.vehiclerecycling.entity.User;
import com.thornbird.vehiclerecycling.exception.ForbiddenException;
import com.thornbird.vehiclerecycling.exception.NotFoundException;
import com.thornbird.vehiclerecycling.exception.ValidationException;
import com.thornbird.vehiclerecycling.model.record.ConfigRecord;
import com.thornbird.vehiclerecycling.model.record.OrderRecord;
import com.thornbird.vehiclerecycling.model.record.PageList;
import com.thornbird.vehiclerecycling.model.record.UserRecord;
import com.thornbird.vehiclerecycling.model.response.Result;
import com.thornbird.vehiclerecycling.service.ConfigService;
import com.thornbird.vehiclerecycling.service.OrderService;
import com.thornbird.vehiclerecycling.service.UserService;
import com.thornbird.vehiclerecycling.util.DateUtil;
import com.thornbird.vehiclerecycling.util.ResultUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;

@RestController
@RequestMapping("/api")
public class ApiController {

    private final OrderService orderService;

    private final UserService userService;

    private final ConfigService configService;

    @Autowired
    public ApiController(OrderService orderService, UserService userService, ConfigService configService) {
        this.orderService = orderService;
        this.userService = userService;
        this.configService = configService;
    }

    @RequestMapping(method = RequestMethod.GET, value = "/ping")
    public Result<String> ping() {
        return ResultUtil.success("pong");
    }

    @RequestMapping(method = RequestMethod.GET, value = "/currentUser")
    public Result<UserRecord> currentUser(HttpServletRequest request) {
        UserRecord userRecord = null;
        HttpSession session = request.getSession(false);
        if (session != null) {
            userRecord = (UserRecord) session.getAttribute(OAuth2LoginConfig.CURRENT_USER);
        }
        return ResultUtil.success(userRecord);
    }

    @RequestMapping(method = RequestMethod.GET, value = "/orders")
    public Result<PageList<OrderRecord>> findOrders(String keyword,
                                                    @DateTimeFormat(pattern = DateUtil.DATE_FORMAT) Date startDate,
                                                    @DateTimeFormat(pattern = DateUtil.DATE_FORMAT) Date endDate,
                                                    Integer pageNumber, Integer pageSize) {
        return ResultUtil.success(orderService.findOrders(keyword, startDate, endDate, pageNumber, pageSize));
    }

    @RequestMapping(method = RequestMethod.GET, value = "/order/{id}")
    public Result<OrderRecord> findOrder(@PathVariable(value = "id") Long id) throws NotFoundException {
        return ResultUtil.success(orderService.findOrder(id));
    }

    @RequestMapping(method = RequestMethod.POST, value = "/order/{id}")
    public Result<OrderRecord> saveOrder(@PathVariable(value = "id") Long id, Order order, Boolean generateCheckCode,
                                         @CurrentUser UserRecord userRecord)
            throws NotFoundException, ValidationException, ForbiddenException {
        if (id <= 0) {
            order.setId(null);
        } else if (!id.equals(order.getId())) {
            throw new ValidationException("invalid id");
        }
        return ResultUtil.success(orderService.saveOrder(order, generateCheckCode, userRecord));
    }

    @RequestMapping(method = RequestMethod.DELETE, value = "/order/{id}")
    public Result<OrderRecord> deleteOrder(@PathVariable(value = "id") Long id, @CurrentUser UserRecord userRecord)
            throws NotFoundException, ValidationException, ForbiddenException {
        return ResultUtil.success(orderService.deleteOrder(id, userRecord));
    }

    @RequestMapping(method = RequestMethod.GET, value = "/users")
    public Result<PageList<UserRecord>> findUsers(String keyword, Integer pageNumber, Integer pageSize,
                                                  @CurrentUser UserRecord userRecord) throws ForbiddenException {
        if (!userService.isSuperUser(userRecord)) {
            throw new ForbiddenException();
        }
        return ResultUtil.success(userService.findUsers(keyword, pageNumber, pageSize));
    }

    @RequestMapping(method = RequestMethod.POST, value = "/user/{id}")
    public Result<UserRecord> saveUser(@PathVariable(value = "id") Long id, User user,
                                        @CurrentUser UserRecord userRecord)
            throws NotFoundException, ValidationException, ForbiddenException {
        if (!userService.isSuperUser(userRecord)) {
            throw new ForbiddenException();
        }
        if (!id.equals(user.getId())) {
            throw new ValidationException("invalid id");
        }
        return ResultUtil.success(userService.saveUser(user));
    }

    @RequestMapping(method = RequestMethod.GET, value = "/config")
    public Result<ConfigRecord> findConfig(@CurrentUser UserRecord userRecord) throws ForbiddenException {
        if (!userService.isSuperUser(userRecord)) {
            throw new ForbiddenException();
        }
        return ResultUtil.success(configService.findConfig());
    }

    @RequestMapping(method = RequestMethod.POST, value = "/config")
    public Result<ConfigRecord> saveOrder(Config config, @CurrentUser UserRecord userRecord)
            throws ForbiddenException {
        if (!userService.isSuperUser(userRecord)) {
            throw new ForbiddenException();
        }
        return ResultUtil.success(configService.saveConfig(config));
    }

}
